package cn.tac.framework.core.pojo;

import cn.tac.framework.core.spring.bean.BizDataInterface;
import cn.tac.framework.core.util.BeanUtils;
import cn.tac.framework.core.util.SpringUtils;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OrderBy;
import java.io.Serializable;
import java.util.Date;

/**
 * 通用实体模型基类
 *
 * <p>如果是与业务相关的实体模型请使用{@link GenericBizModel}</p>
 *
 * <p>
 *     由于使用了泛型主键，在运行时id的类型将被擦除为{@link Object}，因此使用{@link BeanUtils}
 *     将实体类的值复制到dto对象时将无法正常复制id，解决方案有二：
 *     <ul>
 *         <li>在实际代码中手动赋值：{@code dto.setPk(entity.getPk())}</li>
 *         <li>将dto中的id类型更改为{@link Object}</li>
 *     </ul>
 * </p>
 *
 * @see IGenericModel
 * @author : tac
 * @since : 2017/7/14
 */

@Entity
public abstract class GenericModel<PK> implements IGenericModel<PK>, Serializable {
    @Id
    @Column(name = "id")
    private PK pk;
    private String by;
    @OrderBy("desc")
    private Date on;
    private String updateBy;
    private Date updateOn;

    @Override
    public PK getPk() {
        return pk;
    }

    @Override
    public void setPk(PK pk) {
        this.pk = pk;
    }

    public String getBy() {
        return by;
    }

    public void setBy(String by) {
        this.by = by;
    }

    public Date getOn() {
        return on;
    }

    public void setOn(Date on) {
        this.on = on;
    }

    public String getUpdateBy() {
        return updateBy;
    }

    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }

    public Date getUpdateOn() {
        return updateOn;
    }

    public void setUpdateOn(Date updateOn) {
        this.updateOn = updateOn;
    }

    /**
     * {@inheritDoc}
     *
     * @see #newPk()
     * @see #setDef()
     */
    @Override
    public void init(){
        setPk(newPk());
        setBy(SpringUtils.getBean(BizDataInterface.class).currentUserId());
        setOn(new Date());
        setUpdateBy(null);
        setUpdateOn(null);

        setDef();
    }

    /**
     * 在派生类中可以通过改写该方法来为某些字段赋于默认值
     */
    protected void setDef(){
    }

    protected abstract PK newPk();
}
